using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using GADemo.FitnessProviders;
using GeneticAlgorithms;
using GeneticAlgorithms.Alphabets;
using GeneticAlgorithms.ComponentModel;
using GeneticAlgorithms.Factories;
using GeneticAlgorithms.Genomes;
using GeneticAlgorithms.Operators.Crossover;
using GeneticAlgorithms.Operators.Fitness;
using GeneticAlgorithms.Operators.Initialization;
using GeneticAlgorithms.Operators.Mating;
using GeneticAlgorithms.Operators.Mutation;
using GeneticAlgorithms.Operators.Selection;
using GeneticAlgorithms.Populations;

namespace GADemo
{
    public partial class NewPopulationForm : Form
    {
        public NewPopulationForm()
        {
            InitializeComponent();

            Type popType = typeof(IPopulation);

            Assembly assm = Assembly.GetAssembly(typeof(IGeneticAlgorithm));
            Type[] types = assm.GetTypes();
            PopulateCombobox(typeof(IPopulation),
                types, cmbPopType);

            PopulateCombobox(typeof(IGeneticInitializer<>),
                types, cmbInit);
            PopulateCombobox(typeof(IGeneticSelector<IGenome<int>, int>),
                types, cmbSelection);
            PopulateCombobox(typeof(IGeneticMater<IGenome<int>,int>),
                types, cmbMating);
            PopulateCombobox(typeof(IGeneticCrossover<IGenome<int>, int>),
                types, cmbCrossover);
            PopulateCombobox(typeof(IGeneticMutator<>),
                types, cmbMutation);
        }

        private static void PopulateCombobox(
            Type baseType, IEnumerable<Type> types,
            ComboBox cmb)
        {
            foreach (Type t in types)
            {
                if ((!t.IsAbstract) && (!t.IsInterface))
                {
                    if (t.GetInterface(baseType.Name) != null)
                        cmb.Items.Add(new TypeWrapper(t));
                }
            }

            if (cmb.Items.Count > 0)
                cmb.SelectedItem = cmb.Items[0];

        }

        private class TypeWrapper
        {
            public TypeWrapper(Type t)
            {
                innerType = t;
            }

            private readonly Type innerType;

            public Type Type
            {
                get { return innerType; }
            }

            private string CreateFriendlyName()
            {
                StringBuilder sb = new StringBuilder();
                string s = innerType.Name.Replace("Population", String.Empty);
                foreach (char c in s)
                {
                    if (Char.IsUpper(c) && (sb.Length != 0))
                        sb.Append(' ');

                    if (Char.IsLetter(c))
                        sb.Append(c);
                }

                return sb.ToString();
            }

            public override string ToString()
            {
                object[] attrs = 
                    innerType.GetCustomAttributes(typeof(FriendlyNameAttribute), false);
                if ((attrs != null) && (attrs.Length > 0))
                {
                    FriendlyNameAttribute attr = (FriendlyNameAttribute)
                        attrs[0];

                    return attr.FriendlyName;
                }

                return CreateFriendlyName();
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            geneticAlgorithm = null;
            DialogResult = DialogResult.Cancel;
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            try
            {
                double mutationProb;
                if (nudPopSize.Value <= 0)
                {
                    MessageBox.Show("Invalid population populationSize");
                    return;
                }

                if ((nudEliteSize.Value < 0) ||
                    (nudEliteSize.Value > nudPopSize.Value))
                {
                    MessageBox.Show("Elite populationSize must be a value between 0 and pop populationSize");
                    return;
                }

                if (!double.TryParse(txbMutationProb.Text, out mutationProb))
                {
                    MessageBox.Show("Invalid mutation probability");
                    return;
                }
                IAlphabet<char> charAlphabet = new LettersAlphabet(LetterCases.Uppercase);
                ArrayGenome<char> baseGenome = new ArrayGenome<char>(charAlphabet,
                    "HelloWorld".Length);

                IGenomeFactory<IGenome<char>> factory =
                    new CloneableGenomeFactory<IGenome<char>>(
                    baseGenome);

                IFitnessProvider<IGenome<char>, char> fitnessProvider = new HelloWorldFitnessProvider();

                IGeneticInitializer<char> initializer =
                    (IGeneticInitializer<char>)
                    Activator.CreateInstance(
                    ((TypeWrapper)cmbInit.SelectedItem).Type
                    .MakeGenericType(typeof(char)));
                IGeneticSelector<ArrayGenome<char>, char> selector =
                    (IGeneticSelector<ArrayGenome<char>, char>)
                    Activator.CreateInstance(
                    ((TypeWrapper)cmbSelection.SelectedItem).Type
                    .MakeGenericType(typeof(char)));
                IGeneticMater<ArrayGenome<char>, char> mater =
                    (IGeneticMater<ArrayGenome<char>, char>)
                    Activator.CreateInstance(
                    ((TypeWrapper)cmbMating.SelectedItem).Type
                    .MakeGenericType(typeof(char)));
                IGeneticCrossover<ArrayGenome<char>, char> crossover =
                    (IGeneticCrossover<ArrayGenome<char>, char>)
                    Activator.CreateInstance(
                    ((TypeWrapper)cmbCrossover.SelectedItem).Type
                    .MakeGenericType(typeof(char)));
                IGeneticMutator<char> mutator =
                    (IGeneticMutator<char>)
                    Activator.CreateInstance(
                    ((TypeWrapper)cmbMutation.SelectedItem).Type
                    .MakeGenericType(typeof(char)));
                
                mutator.MutationProbability = mutationProb;
               
                IPopulation<ArrayGenome<char>, char> pop =
                    (IPopulation<ArrayGenome<char>, char>)
                    Activator.CreateInstance(
                    ((TypeWrapper)cmbPopType.SelectedItem).Type
                    .MakeGenericType(typeof(char)),
                    (int)nudPopSize.Value, factory,
                    fitnessProvider, initializer,
                    selector, mater, crossover,
                    mutator
                    );

                pop.EliteSize = (int)nudEliteSize.Value;

                GAConfigurationBase config = new GAConfigurationBase();
                config.MaxGenerations = 1000;
                config.DesiredFitness = 100;

                geneticAlgorithm = new GeneticAlgorithm<ArrayGenome<char>, char>(pop, config);

                DialogResult = DialogResult.OK;
            }
            catch (Exception error)
            {
                MessageBox.Show("Unable to create genetic algorithm"
                    + Environment.NewLine + "Exception message:" +
                    Environment.NewLine + error.Message);

                DialogResult = DialogResult.Cancel;
            }
        }

        private IGeneticAlgorithm geneticAlgorithm;

        public IGeneticAlgorithm GeneticAlgorithm
        {
            get { return geneticAlgorithm; }
        }
	
    }


}